﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SuperListLibrary;

/*
 * Author : Daniel Mcliver
 */
namespace SuperListTest
{
    [TestClass]
    public class SuperListTest
    {
        [TestMethod]
        public void ShiftRightOperator_WithListAndNonNegativeShiftNumber_ShiftsNTimes()
        {
            SuperList<int> list = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

            list = list >> 3;

            Assert.AreEqual(7, list.Count);
            Assert.AreEqual(7, list[6]);
        }

        [TestMethod]
        public void ShiftRightOperator_WithListAndNegativeShiftNumber_ShiftsZeroTimes()
        {
            SuperList<int> list = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

            list = list >> -3;

            Assert.AreEqual(10, list.Count);
            Assert.AreEqual(0, list[9]);
        }

        [TestMethod]
        public void ShiftRightOperator_WithListAndShiftAmountGreaterThanListSize_ReturnsEmptyList()
        {
            SuperList<int> list = new SuperList<int> { 1, 2, 3, 4, 5 };

            list = list >> 8;

            Assert.AreEqual(0, list.Count);
        }

        [TestMethod]
        public void ShiftRightOperator_WithListAndShiftAmountTheSameAsListSize_ReturnsEmptyList()
        {
            SuperList<int> list = new SuperList<int> {1, 2, 3, 4, 5};

            list = list >> 5;

            Assert.AreEqual(0, list.Count);
        }

        [TestMethod]
        public void ShiftLeftOperator_WithListAndNonNegativeShiftNumber_ShiftsNTimes()
        {
            SuperList<int> list = new SuperList<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
            
            list = list << 3;

            Assert.AreEqual(7,list.Count);
            Assert.AreEqual(4, list[0]);
        }

        [TestMethod]
        public void ShiftLeftOperator_WithListAndNegativeShiftNumber_ShiftsZeroTimes()
        {
            SuperList<int> list = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

            list = list << -3;

            Assert.AreEqual(10, list.Count);
            Assert.AreEqual(1, list[0]);
        }

        [TestMethod]
        public void ShiftLeftOperator_WithListAndShiftAmountGreaterThanListSize_ReturnsEmptyList()
        {
            SuperList<int> list = new SuperList<int> { 1, 2, 3, 4, 5 };

            list = list << 8;

            Assert.AreEqual(0, list.Count);
        }

        [TestMethod]
        public void ToSuperList_WithListAsIEnumerable_ConvertsToSuperList()
        {
            IEnumerable<int> list = new SuperList<int> {1, 2, 3, 4, 5};
            SuperList<int> sList = list.ToSuperList();

            Assert.IsNotNull(sList);
            Assert.AreEqual(5, sList.Count);
        }

        [TestMethod]
        public void ToSuperList_WithNormalListAsIEnumerable_ConvertsToSuperList()
        {
            IEnumerable<int> list = new List<int> { 1, 2, 3, 4, 5 };
            SuperList<int> sList = list.ToSuperList();

            Assert.IsNotNull(sList);
            Assert.AreEqual(5, sList.Count);
        }

        [TestMethod]
        public void AddOperator_WithItem_AddsItemToEndOfList()
        {
            var list = new SuperList<int> { 1, 2, 3, 4, 5 };
            
            list += 6;

            Assert.AreEqual(6, list.Count);
            Assert.AreEqual(6, list[5]);
        }

        [TestMethod]
        public void AddOperator_AddAndAssignment_AddsLists()
        {
            var list = new SuperList<int> {1, 2, 3, 4, 5};

            list += new SuperList<int>{6,7,8};
            
            Assert.AreEqual(8,list.Count);

            Assert.AreEqual(6,list[5]);
            Assert.AreEqual(8, list[7]);
            Assert.AreEqual(1, list[0]);
            Assert.AreEqual(3, list[2]);
            Assert.AreEqual(5, list[4]);
        }

        [TestMethod]
        public void AddOperator_WithTwoLists_AddsLists()
        {
            SuperList<int> summedList = new SuperList<int> {1, 2, 3} + new SuperList<int> { 4, 5, 6 };

            var expected = new SuperList<int> {1, 2, 3, 4, 5, 6};

            Assert.AreEqual(expected.Count,summedList.Count);

            for (int i = 0; i < summedList.Count; i++)
            {
                Assert.AreEqual(expected[i],summedList[i]);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddOperator_WithNullList_AddsLists()
        {
            var val = new SuperList<int> { 1, 2, 3 } + null;
        }

        [TestMethod]
        public void DivideOperator_WithListAndIntegerVal_DividesList()
        {
            IEnumerable<List<int>> splices = new SuperList<int> { 1, 2, 3 } / 2;
            var enumerable = splices as IList<List<int>> ?? splices.ToList();
            Assert.AreEqual(2,enumerable.Count());
            Assert.AreEqual(1,enumerable.First().Count);
            Assert.AreEqual(1,enumerable.First().First());
            Assert.AreEqual(2,enumerable.Last().Count);
        }

        [TestMethod]
        [ExpectedException(typeof(DivideByZeroException))]
        public void DivideOperator_WithListAndIntegerValThatsZero_ThrowsExpection()
        {
            IEnumerable<SuperList<int>> enumerable = new SuperList<int> {1, 2, 3}/0;
        }

        [TestMethod]
        public void DivideOperator_WithListAndIntegerValThatsNegative_EmptiesList()
        {
            var list = new SuperList<int> { 1, 2, 3 } / -6;
            Assert.AreEqual(0, list.Count());
        }

        [TestMethod]
        public void MultipleOperator_WithNonZeroMultiplier_DuplicatesList()
        {
            const int multiplier = 2;
            List<int> multiples = new SuperList<int> { 1, 2, 3 } * multiplier;

            Assert.AreEqual(multiplier,multiples.Count(m => m==1));
            Assert.AreEqual(multiplier,multiples.Count(m => m==multiplier));
            Assert.AreEqual(multiplier,multiples.Count(m => m==3));

        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void MultipleOperator_WithNegativeMultiplier_ThrowsExpection()
        {
            const int multiplier = -2;
            SuperList<int> superList = new SuperList<int> {1, 2, 3}*multiplier;
        }

        [TestMethod]
        public void MultipleOperator_WithZeroMultiplier_EmptiesList()
        {
            const int multiplier = 0;
            List<int> multiples = new SuperList<int> { 1, multiplier, 3 } * multiplier;

            Assert.AreEqual(multiplier,multiples.Count);
            Assert.AreEqual(multiplier, multiples.Count(m => m == 1));
            Assert.AreEqual(multiplier, multiples.Count(m => m == multiplier));
            Assert.AreEqual(multiplier, multiples.Count(m => m == 3));

        }

        [TestMethod]
        public void RemoveAt_WithAbsoluteValuesForIndexAndAmount_RemovesSpecifiedAmountAtLocation()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.RemoveAt(3, 3);
            var expected = new SuperList<int> {1, 2, 3, 7};
            for (int i = 0; i < expected.Count; i++)
            {
                Assert.AreEqual(expected[i],superList[i]);
            }
        }

        [TestMethod]
        public void RemoveAt_WithZeroValuesForIndexAndAmount_RemovesNothing()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.RemoveAt(3, 0);
            var expected = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            for (int i = 0; i < expected.Count; i++)
            {
                Assert.AreEqual(expected[i], superList[i]);
            }
        }

        [TestMethod]
        public void RemoveAt_WithNegativeValuesForIndexAndAmount_RemovesNothing()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.RemoveAt(3, -1);

            Assert.AreEqual(7,superList.Count);
           
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void RemoveAt_WithNegativeValuesForIndex_ThrowsException()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.RemoveAt(-3, 2);

            Assert.AreEqual(7, superList.Count);

        }

        [TestMethod]
        public void InsertAt_WithAbsoluteValueForIndexAndValidList_InsertsElements()
        {
            var superList = new SuperList<int> {1, 2, 3, 4, 5, 6, 7};
            superList.Insert(2,new SuperList<int>{8 ,9 ,0});
            var expected = new SuperList<int> {1, 2, 8, 9, 0, 3, 4, 5, 6, 7};
            for (int i = 0; i < expected.Count; i++)
            {
                Assert.AreEqual(expected[i],superList[i]);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void InsertAt_WithNegativeValueForIndexAndValidList_ThrowsException()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.Insert(-1, new SuperList<int> { 8, 9, 0 });

        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void InsertAt_WithNullList_ThrowsException()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.Insert(3, null);

        }

        [TestMethod]
        public void InsertAt_WithEmptyList_InsertsNothing()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            superList.Insert(3, new SuperList<int>());
            Assert.AreEqual(7,superList.Count);
        }

        [TestMethod]
        public void Contains_WithValidItemsContainedInList_ReturnsTrueForInSequence()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(new SuperList<int> {2, 3, 4}, true);
            Assert.IsTrue(contains);
        }

        [TestMethod]
        public void Contains_WithValidItemsNotContainedInList_ReturnsFalseForInSeq()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(new SuperList<int> { 1, 3, 4 }, true);
            Assert.IsFalse(contains);
        }

        [TestMethod]
        public void Contains_WithValidItemsContainedInList_ReturnsTrueForNotInSequence()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(new SuperList<int> { 3, 2, 4 }, false);
            Assert.IsTrue(contains);
        }

        [TestMethod]
        public void Contains_WithValidItemsNotContainedInList_ReturnsFalseForNotInSeq()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(new SuperList<int> { 9, 3, 4 }, false);
            Assert.IsFalse(contains);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Contains_WithNullCollection_ThrowsError()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(null, false);
            Assert.IsFalse(contains);
        }

        [TestMethod]
        public void Contains_WithEmptyList_ReturnsTrue()
        {
            var superList = new SuperList<int> { 1, 2, 3, 4, 5, 6, 7 };
            bool contains = superList.Contains(new SuperList<int> { }, false);
            contains |= superList.Contains(new SuperList<int> { }, true);
            Assert.IsFalse(contains);
        }

        [TestMethod]
        public void Contains_WithCollectionOfElementsLargerThanList_ReturnsTrueIfElementsAreInList()
        {
            var superList = new SuperList<int> { 1, 2, 3 };
            bool contains = superList.Contains(new SuperList<int> {1,2,3,4,5 }, true);
            contains |= superList.Contains(new SuperList<int> {3,5,2,1,4 }, false);
            Assert.IsTrue(contains);
        }
    }
}
